#!/usr/bin/env python

import os, sys
import random, urllib

from liwe.module import LiweModule

class Banner ( LiweModule ):

	def __init__ ( self, liwe ):
		super ( Banner, self ).__init__ ( liwe, "banner" )

		self.dbm = self.liwe.dbm


	# {{{ GROUPS MANAGEMENT
	def group_add ( self, name, enabled, expiration ):
		"""
		group_add ( name, enabled, expiration )

		:DESCR:
			Aggiunge un nuovo gruppo
		"""

		if not expiration: expiration = "*NULL"

		self.dbm.insert ( "banner_group", { "created": "*NOW()", "name": name, "enabled": enabled, "expiration": expiration } )
		return self.dbm.insert_id ()


	def group_change ( self, id_group, name, enabled, expiration ):
		"""
		group_change ( id_group, name, enabled, expiration )

		:DESCR:
			Modifica un gruppo esistente
		"""

		self.dbm.update ( "banner_group", { "name": name, "enabled": enabled, "expiration": expiration }, "id = %s" % id_group )


	def group_del ( self, ids ):
		"""
		group_del ( ids )

		:DESCR:
			Elimina uno o piu' gruppo
		"""

		self.dbm.delete ( "banner_group", "id IN ( %s )" % ", ".join ( ids.split ( "|" ) ) )


	def group_list ( self, start_point = 0, limit = 10 ):
		"""
		group_list ( start_point, limit )

		:DESCR:
			Restituisce l'elenco dei gruppi
		"""
		extras = " ORDER BY name LIMIT %s, %s" % ( start_point, limit )

		tables = "banner_group"
		fields = "*"
		conds = ""

		tot_rows = self.dbm.count ( tables, fields, conds )

		cur = self.dbm.select ( tables, fields, conds, extras = extras )

		rows = []

		if cur:
			for r in cur:
				#self.list_manip ( r )
				rows.append ( r )

			cur.close ()

		return { "rows" : rows, "tot_rows" : tot_rows }



	def group_get ( self, id_group ):
		"""
		group_get ( id_group )

		:DESCR:
			Restituisce un gruppo
		"""

		return self.dbm.single_row ( "banner_group", "*", "id = %s" % id_group )
	# }}}

	# {{{ CONTAINERS MANAGEMENT
	def container_add ( self, name, issue_rate, width, height ):
		"""
		container_add ( name, issue_rate, width, height )

		:DESCR:
			Aggiunge un nuovo contenitore
		"""

		self.dbm.insert ( "banner_container", { "created": "*NOW()", "name": name, "issue_rate": issue_rate,
			"width": width, "height": height } )
		return self.dbm.insert_id ()


	def container_change ( self, id_cont, name, issue_rate, width, height ):
		"""
		container_change ( id_cont, name, issue_rate, width, height )

		:DESCR:
			Modifica un contenitore esistente
		"""

		self.dbm.update ( "banner_container", { "name": name, "issue_rate": issue_rate,
			"width": width, "height": height }, "id = %s" % id_cont )


	def container_del ( self, ids ):
		"""
		container_del ( ids )

		:DESCR:
			Elimina uno o piu' contenitori
		"""

		self.dbm.delete ( "banner_container", "id IN ( %s )" % ", ".join ( ids.split ( "|" ) ) )



	def container_list ( self ):
		"""
		container_list ()

		:DESCR:
			Restituisce l'elenco dei contenitori
		"""

		rs = self.dbm.select ( "banner_container", "*", extras = "ORDER BY name" )
		if rs:
			res = rs.fetchall ()
			rs.close ()
		else:
			res = []

		return res

	def container_list2 ( self, start_point = 0, limit = 10 ):
		"""
		container_list ( start_point, limit )

		:DESCR:
			Restituisce l'elenco dei contenitori
		"""
		extras = " ORDER BY name LIMIT %s, %s" % ( start_point, limit )

		tables = "banner_container"
		fields = "*"
		conds = ""

		tot_rows = self.dbm.count ( tables, fields, conds )

		cur = self.dbm.select ( tables, fields, conds, extras = extras )

		rows = []

		if cur:
			for r in cur:
				#self.list_manip ( r )
				rows.append ( r )

			cur.close ()

		return { "rows" : rows, "tot_rows" : tot_rows }


	def container_get ( self, id_cont ):
		"""
		container_get ( id_cont )

		:DESCR:
			Restituisce un contenitore
		"""

		return self.dbm.single_row ( "banner_container", "*", "id = %s" % id_cont )
	# }}}

	# {{{ BANNER MANAGEMENT
	def banner_add ( self, id_container, id_group, url_click, popup, issue_rate, view_time ):
		"""
		banner_add ( id_container, id_group, url_click, popup, issue_rate, view_time )

		:DESCR:
			Aggiunge un nuovo banner
		"""

		self.dbm.insert ( "banner_file", { "created": "*NOW()", "issue_rate": issue_rate, "url_click": url_click,
			"popup": popup, "id_container": id_container, "id_group": id_group, "view_time": view_time } )
		return self.dbm.insert_id ()


	def banner_change ( self, id_banner, id_container, id_group, url_click, popup, issue_rate, view_time ):
		"""
		banner_change ( id_banner, id_container, id_group, url_click, popup, issue_rate, view_time )

		:DESCR:
			Modifica un banner esistente
		"""

		self.dbm.update ( "banner_file", { "issue_rate": issue_rate, "url_click": url_click,
                        "popup": popup, "id_container": id_container, "id_group": id_group, "view_time": view_time }, "id = %s" % id_banner )


	def banner_del ( self, ids ):
		"""
		banner_del ( ids )

		:DESCR:
			Elimina uno o piu' banner
		"""

		self.dbm.delete ( "banner_file", "id IN ( %s )" % ", ".join ( ids.split ( "|" ) ) )

		from modules.media_manager.media_manager_class import MediaManager
		mm  = MediaManager ( self.liwe )

		_banners = ids.split ( "|" )
		for b in _banners:
			mm.del_items ( "banner", int ( b ) )


	def banner_get ( self, id_banner ):
		"""
		banner_get ( id_banner )

		:DESCR:
			Restituisce un banner
		"""

		return self.dbm.single_row ( "banner_file", "*", "id = %s" % id_banner )


	def banner_list ( self, id_group = None, id_container = None ):
		"""
		banner_list ()

		:DESCR:
			Restituisce l'elenco dei banner (eventualmente filtrato)
		"""

		conds = []

		if id_group: conds.append ( "id_group = %s" % id_group )
		if id_container: conds.append ( "id_container = %s" % id_container )

		rs = self.dbm.select ( "banner_file", "*", " AND ".join ( conds ), extras = "ORDER BY created DESC" )
		res = []
		if rs:
			for r in rs:
				mres = self.get_media_items ( r [ "id" ] )

				r [ "media" ] = mres
				r [ '_img' ] = ''
				if r.get ( 'media' ) and r [ 'media' ] [ 0 ]:
					media = r [ 'media' ] [ 0 ]
					r [ '_img' ] = media [ 'html' ] % { "_size" : "icon", "_ext" : ".jpg" }
				
				res.append ( r )

		return res

	def banner_list2 ( self, start_point = 0, limit = 10 ):
		"""
		banner_list ( start_point, limit )

		:DESCR:
			Restituisce l'elenco dei banners
		"""
		extras = " ORDER BY created LIMIT %s, %s" % ( start_point, limit )

		tables = "banner_file"
		fields = "*"
		conds = ""

		tot_rows = self.dbm.count ( tables, fields, conds )

		cur = self.dbm.select ( tables, fields, conds, extras = extras )

		rows = []

		if cur:
			for r in cur:
				mres = self.get_media_items ( r [ "id" ] )

				r [ "media" ] = mres
				r [ '_img' ] = ''
				if r.get ( 'media' ) and r [ 'media' ] [ 0 ]:
					media = r [ 'media' ] [ 0 ]
					r [ '_img' ] = media [ 'html' ] % { "_size" : "icon", "_ext" : ".jpg" }
				rows.append ( r )

			cur.close ()

		return { "rows" : rows, "tot_rows" : tot_rows }


	def banner_set_media ( self, id_banner, id_media ):
		"""
		banner_set_media ( id_banner, id_media )

		:DESCR:
			Imposta il l'id del MediaManager al banner specificato
		"""

		self.dbm.update ( "banner_file", { "id_media": id_media }, "id = %s" % id_banner )
	# }}}

# {{{ COUNTERS & STATS
	def counter_inc ( self, id_banner, kind ):
		r = self.dbm.single_row ( "banner_count", "*", "id_file = %s AND kind = %s" % ( id_banner, kind ) )
		if r:
			self.dbm.update ( "banner_count", { "count": "*count + 1" }, "id_file = %s AND kind = %s" % ( id_banner, kind ) )
		else:
			self.dbm.insert ( "banner_count", { "id_file": id_banner, "kind": kind, "count": 1 } )


	"""
	def get_counters ( self ):
		tables = [ "banner_count AS c", "banner_file AS f", "banner_container AS cnt", "banner_group AS g" ]
		fields = [ "f.id", "cnt.name AS container", "g.name AS grp", "f.url_click", "c.kind", "c.count" ]
		conds = "c.id_file = f.id AND f.id_container = cnt.id AND f.id_group = g.id"

		rs = self.dbm.select ( tables, fields, conds, extras = "ORDER BY c.count DESC" )
		if not rs: rs = []

		res = {}

		for r in rs:
			k = r [ "id" ]
			kind = r [ "kind" ]
			count = r [ "count" ]

			if kind == 0: kind = "view"
			else: kind = "click"

			if not res.get ( k ):
				del r [ "kind" ]
				del r [ "count" ]

				mres = self.get_media_items ( k )

				r [ '_img' ] = ''
				if mres and mres [ 0 ]:
					media = mres [ 0 ]
					r [ '_img' ] = media [ 'html' ] % { "_size" : "icon", "_ext" : ".jpg" }

				res [ k ] = r

			res [ k ] [ "count_" + kind ] = count

		return res.values ()
	"""

	def counters_list ( self, mode = 0, container = 0, start_point = 0, limit = 10 ):
		"""
		counters_list ( start_point, limit )
	
		:INPUT:
			- mode:		0 == ORDER BY view, click
					1 == ORDER BY click, view

			- container:	container_id to filter on. 0 == no filter

		:DESCR:
			Restituisce l'elenco dei contatori totali
		"""

		"""
		select b.id, click.count AS click, view.count AS view FROM banner_file AS b, banner_count AS click, banner_count AS view  WHERE b.id = click.id_file AND b.id = view.id_file AND view.kind = 0 AND click.kind = 1;
		"""

		if mode == 0:
			extras = "ORDER BY count_view DESC, count_click DESC"
		else:
			extras = "ORDER BY count_click DESC, count_view DESC"

		extras += " LIMIT %s, %s" % ( start_point, limit )


		tables = [ "banner_file AS b", 
			   "banner_container AS cnt", 
			   "banner_group AS g",
			   "banner_count AS click",
			   "banner_count AS view" ]

		fields = [ "b.id", "cnt.name AS container", "g.name AS grp", "b.url_click", "view.count AS count_view", "click.count AS count_click"  ]

		conds = [ "b.id_container = cnt.id",
			  "b.id_group = g.id",
			  "b.id = click.id_file",
			  "b.id = view.id_file",
			  "view.kind = 0",
			  "click.kind = 1" ]

		# TODO:
		# if container != 0, aggiungere condizione di filtro

		conds = " AND ".join ( conds )
		tot_rows = self.dbm.count ( tables, fields, conds )

		#self.dbm.debug = sys.stderr.write
		cur = self.dbm.select ( tables, fields, conds, extras = extras )

		rows = []

		if cur:
			for r in cur:
				k = r [ "id" ]

				mres = self.get_media_items ( k )

				r [ '_img' ] = ''
				if mres and mres [ 0 ]:
					media = mres [ 0 ]
					r [ '_img' ] = media [ 'html' ] % { "_size" : "icon", "_ext" : ".jpg" }

				rows.append ( r )

			cur.close ()

		return { "rows" : rows, "tot_rows" : tot_rows }


	def get_stats ( self, start = '', end = '' ):
		from modules.stats.stats_class import Stats
		s = Stats ( self.liwe )
		events = s.list_events ( module = "banner", start = start, end = end )

		banner_ids = set ( [ e [ "id_obj" ] for e in events ] )

		tables = [ "banner_file AS f", "banner_container AS cnt", "banner_group AS g" ]
		fields = [ "f.id", "cnt.name AS container", "g.name AS grp", "f.url_click" ]
		conds = "f.id_container = cnt.id AND f.id_group = g.id"

		rs = self.dbm.select ( tables, fields, conds + " AND f.id IN ( %s )" % ", ".join ( banner_ids ) )
		if not rs: rs = []

		banners = {}

		for r in rs:
			k = str ( r [ "id" ] )
			banners [ k ] = r

		for e in events:
			b = banners.get ( e [ "id_obj" ] )
			if b: e.update ( b )

		return events
# }}}

	# {{{ PUBLIC INTERFACE
	def banner_fetch ( self, container = None ):
		"""
		banner_fetch ( container )

		:DESCR:
			Recupera un banner (per mostrarlo)
		"""

		if container:
			#il contenitore e' stato specificato,
			# andiamo a pescarlo da db
			cont = self.dbm.single_row ( "banner_container", "*", "name = '%s'" % container )
			if not cont:
				self.liwe.pyhp.err_code = 2
				self.liwe.pyhp.err_descr = "Impossibile trovare il container specificato"
				return

		else:
			#altrimenti devo scegliere un contenitore
			db_conts = self.dbm.select ( "banner_container", "*" )
			if not db_conts:
				self.liwe.pyhp.err_code = 2
				self.liwe.pyhp.err_descr = "Impossibile trovare un container"
				return
			conts = db_conts.fetchall()
			db_conts.close()

			max_rate = 0
			for cont in conts:
				max_rate += int ( cont [ "issue_rate" ] )

			if not max_rate: max_rate = 1
			r = random.randrange ( 10000 ) % max_rate

			cur_rate = 0
			for cont in conts:
				cur_rate += int ( cont [ "issue_rate" ] )
				if r < cur_rate: break

		# OK. ho il contenitore, prelevo i valori
		id_cont = int ( cont [ "id" ] )
		width = int ( cont [ "width" ] )
		height = int ( cont [ "height" ] )

		#devo scegliere un banner
		db_banners = self.dbm.select ( "banner_file", "*", "id_container = %d" % id_cont )
		if not db_banners:
			self.liwe.pyhp.err_code = 2
			self.liwe.pyhp.err_descr = "Impossibile trovare un banner"
			return
		banners = db_banners.fetchall()
		db_banners.close()

		max_rate = 0
		for banner in banners:
			max_rate += int ( banner [ "issue_rate" ] )
		
		if not max_rate: max_rate = 1
		r = random.randrange ( 10000 ) % max_rate

		cur_rate = 0
		for banner in banners:
			cur_rate += int ( banner [ "issue_rate" ] )
			if r < cur_rate: break

		id_banner = int ( banner [ "id" ] )

		#recupero le info sul banner dal MM
		from modules.media_manager.media_manager_class import MediaManager
		mm  = MediaManager ( self.liwe )

		# FIXME: quick fix but need support for new media manager format
		media_items = mm.get_items ( "banner", banner [ 'id' ] ) [ 'media_items' ]
		if media_items:
			media = media_items [ 0 ]

			href = "/ajax.pyhp?action=banner.ajax.banner_click&id_banner=%s" % banner [ "id" ]

			if media [ "kind" ] == "image":
				if banner [ "popup" ]: target = 'target="_blank"'
				else: target = ''

				media [ "html" ] = '<a %s href="%s">' % ( target, href.replace ( "%", "%%" ) ) + media [ "html" ] + '</a>'

				banner [ "media" ] = media

			elif media [ "kind" ] == "flash":
				params = urllib.urlencode ( {
					"dest_url": href,
					"banner": '/site/media_manager/flash/orig/%s.swf' % media [ "id_media" ],
					"param_target": banner [ "popup" ] and "_blank" or ""
				} )
				swf = '/modules/banner/player.swf?' + params

				dct = {
					"swf": swf,
					"width": width,
					"height": height
				}

				media [ "html" ] = """<object width="%(width)s" height="%(height)s" >
					<param name="movie" value="%(swf)s"></param>
					<param name="allowFullScreen" value="true"></param>
					<param name="allowscriptaccess" value="always"></param>
					<param name="wmode" value="transparent"></param>
					<embed src="%(swf)s" type="application/x-shockwave-flash" wmode="transparent"
						allowscriptaccess="always" allowfullscreen="true" width="%(width)s" height="%(height)s"></embed>
					</object>""" % dct

				media [ "ext" ] = "swf"

				banner [ "media" ] = media

		#aggiorno i contatori di uscita
		self.counter_inc ( banner [ "id" ], 0 )

		from modules.stats.stats_class import Stats
		s = Stats ( self.liwe )
		s.log ( "banner", str ( banner [ "id" ] ), "view" )

		#Ok. Ho il banner!
		return banner


	def banner_click ( self, id_banner ):
		#aggiorno i contatori di uscita
		self.counter_inc ( id_banner, 1 )

		from modules.stats.stats_class import Stats
		s = Stats ( self.liwe )
		s.log ( "banner", str ( id_banner ), "click" )
	# }}}

